package com.sunriz.ctrl.server.utils.serial;

import com.ghgande.j2mod.modbus.ModbusException;
import com.ghgande.j2mod.modbus.facade.ModbusSerialMaster;
import com.ghgande.j2mod.modbus.procimg.Register;
import com.sunriz.ctrl.server.model.DTO.RegisterInfo;
import com.sunriz.ctrl.server.model.DTO.ScadaConfigDTO;
import com.sunriz.ctrl.server.utils.scada.ScadaConfigUtil;
import com.sunriz.ctrl.views.ScadaController;
import lombok.extern.slf4j.Slf4j;
import java.lang.Thread;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * ClassName: ModbusServer
 * Package: com.sunriz.ctrl.server.utils.scada
 * Description:
 *
 * @Author BuTang
 * @Create 2025/1/15 16:57
 * @Version 1.0
 */
@Slf4j
public class ModbusServer {
    private static ModbusSerialMaster master;

    private static Thread thread;
    private static final AtomicBoolean running = new AtomicBoolean(true);
    private static final Object lock = new Object();

    /**
     * 从json文件中读取配置信息，且进行数据循环读取
     */
    public static void readRegister() {
        log.info("开始读取后台线程中的 Modbus 寄存器...");

        // 创建modbus连接
        master = ModbusRtuManger.getInstance().create();
        List<ScadaConfigDTO> scadaConfigDTOS = ScadaConfigUtil.readScadaConfig();
        running.set(true);



        // 遍历不同的设备
        thread = new Thread(() -> {
            while (running.get()) {
                synchronized (lock) {
                    if (!running.get()) {
                        return; // 如果 running 为 false，直接退出当前的 forEach 循环
                    }

                    scadaConfigDTOS.forEach(scadaConfigDTO -> {

                        // 用于存储设置更新数据到了哪一位index
                        AtomicInteger currentIndex = new AtomicInteger(0);

                        if (!running.get()) {
                            return; // 如果 running 为 false，直接退出当前的 forEach 循环
                        }

                        String slaveId = scadaConfigDTO.getSlaveId();
                        List<RegisterInfo> infos = scadaConfigDTO.getInfos();

                        // 遍历同一个设备内的地址
                        int startAddress = infos.get(0).getAddress();
                        int len = 1;

                        // 从索引1开始遍历
                        for (int i = 1; i < infos.size(); i++) {
                            RegisterInfo registerInfo = infos.get(i);

                            // 如果地址连续（当前地址 = 起始地址 + 当前长度）
                            if (startAddress + len == registerInfo.getAddress()) {
                                len++; // 如果地址连续，增加长度
                            } else {
                                // 地址不连续时，输出当前连续地址的起始值和长度
                                try {
                                    Register[] registerValues  = master.readMultipleRegisters(Integer.parseInt(slaveId), startAddress, len);
                                    for (int j = 0; j < len; j++) {
                                        // 将对应的 value 更新到对应的 RegisterInfo 中
                                        RegisterInfo info = infos.get(currentIndex.get());
                                        info.setValue(String.valueOf(registerValues[j].getValue()));
                                        currentIndex.addAndGet(1);
                                    }
                                    ScadaConfigUtil.updateScadaConfigList(scadaConfigDTOS);

                                } catch (ModbusException e) {
                                    log.error(e.getMessage());
                                    e.printStackTrace();
                                }

                                // 重置起始地址和长度，开始新的连续地址段
                                startAddress = registerInfo.getAddress();
                                len = 1; // 新的地址段长度重新设置为 1
                            }
                        }

                        // 确保最后一个地址段也会被输出
                        try {
                            Register[] registers = master.readMultipleRegisters(Integer.parseInt(slaveId), startAddress, len);
                            for (int j = 0; j < len; j++) {
                                // 将对应的 value 更新到对应的 RegisterInfo 中
                                RegisterInfo info = infos.get(currentIndex.get());
                                info.setValue(String.valueOf(registers[j].getValue()));
                                currentIndex.addAndGet(1);
                            }
                            ScadaConfigUtil.updateScadaConfigList(scadaConfigDTOS);
                        } catch (ModbusException e) {
                            log.error(e.getMessage());
                            e.printStackTrace();
                        }
                    });
                    try {
                        // 等待 0.5 秒后再次发送
                        Thread.sleep(500); // 500 毫秒 = 0.5 秒
                    } catch (InterruptedException e) {
                        log.error("Thread was interrupted during sleep", e);
                        Thread.currentThread().interrupt(); // 保持中断状态
                    }

                }
            }
        });
        thread.start();
    }

    public static void stopRead() {
        running.set(false);
        try {
            synchronized (lock) {
                if (thread != null) {
                    thread.join(200); // 等待线程最多 200 毫秒
                }
            }
        } catch (InterruptedException e) {
            log.error("Thread was interrupted during join", e);
            Thread.currentThread().interrupt(); // 保持中断状态
        }
    }
}